class vec3 {
  num x;
  num y;
  num z;
  
  double get lengthSq() => x * x + y * y + z * z;
  double get length() => Math.sqrt(x * x + y * y + z * z);
 
  vec3(this.x, this.y, this.z);
  
  vec3.xy(num x, num y) {
    this.x = x;
    this.y = y;
    this.z = 0;
  }
  
  vec3.zero() {
    this.x = 0;
    this.y = 0;
    this.z = 0;
  }
  
  vec3.from(vec3 other) {
    this.x = other.x;
    this.y = other.y;
    this.z = other.z;
  }
  
  double dot(vec3 other) {
    return x * other.x + y * other.y + z * other.z;
  }
  
  double distanceSq(vec3 other) {
    final num dx = x - other.x;
    final num dy = y - other.y;
    final num dz = z - other.z;
    return Math.sqrt(dx * dx + dy * dy + dz * dz);
  }
  
  double distance(vec3 other) {
    return Math.sqrt(distanceSq(other));
  }
  
  void normalize() {
    double l = lengthSq;
    if (l != 0.0 && l != 1.0) {
      l = Math.sqrt(l);
      x /= l;
      y /= l;
      z /= l;
    }
  }
  
  vec3 operator + (vec3 right) {
    return new vec3(x + right.x, y + right.y, z + right.z);
  }
  
  vec3 operator - (vec3 right) {
    return new vec3(x - right.x, y - right.y, z - right.z);
  }
  
  vec3 operator * (num right) {
    return new vec3(x * right, y * right, z * right);
  }
  
  vec3 operator / (num right) {
    return new vec3(x / right, y / right, z / right);
  }
  
  static final vec3 Zero = new vec3(0, 0, 0);
  static final vec3 UniX = new vec3(1, 0, 0);
  static final vec3 UniY = new vec3(0, 1, 0);
  static final vec3 UniZ = new vec3(0, 0, 1);
}